package com.huang.service.impl;

import cn.hutool.json.JSONException;
import cn.hutool.json.JSONObject;
import com.huang.service.IDemoService;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;


@Service("demoService")
public class DemoServiceImpl implements IDemoService {

    @Override
    public JSONObject queryBalance(JSONObject userDTO) {
        //初始化返回结果
        JSONObject resultJson = new JSONObject();

        try {
            //判断入参
            if (!"".equals(userDTO.getStr("userId"))) {
                resultJson.put("code", "0001");
                resultJson.put("msg", "用户id不能为空");
                resultJson.put("result", false);
                return resultJson;
            }

            //查询sql语句
            String sql = "select tb_user.balance from tb_user "
                    + " where tb_user.user_id = '"+userDTO.getStr("userId")+"'" ;
            System.out.println("操作mybatis或mybatis plus框架执行上面sql："+sql);
            Integer queryTotal = 1;//查询结果数量
            if (queryTotal > 0){
                resultJson.put("code", "0000");
                resultJson.put("data", sql);//将查询到的json对象put进去
                resultJson.put("msg", "查询成功");
                resultJson.put("result", true);
            }else {
                resultJson.put("code", "0000");
                resultJson.put("msg", "未查询到该用户信息");
                resultJson.put("result", true);
            }
        } catch (JSONException e) {
            log.error("查询用户余额接口出现了异常:",e);
        }

        return resultJson;
    }

    @Override
    public JSONObject consume(JSONObject consumeDTO) {
        //初始化返回结果
        JSONObject resultJson = new JSONObject();

        String consumeId = "",userId = "", consumeMoney = "",remark = "";

        try {

            consumeId = consumeDTO.getStr("consumeId");
            userId = consumeDTO.getStr("userId");
            consumeMoney = consumeDTO.getStr("consumeMoney");//消费金额传入100
            remark = consumeDTO.getStr("remark");

            //判断入参
            if (!"".equals(consumeId)) {
                resultJson.put("code", "0001");
                resultJson.put("msg", "消费id不能为空");
                resultJson.put("result", false);
                return resultJson;
            }
            if (!"".equals(userId)) {
                resultJson.put("code", "0001");
                resultJson.put("msg", "用户id不能为空");
                resultJson.put("result", false);
                return resultJson;
            }
            if (!"".equals(consumeMoney) && new BigDecimal("0").compareTo(new BigDecimal(consumeMoney))<0) {
                resultJson.put("code", "0001");
                resultJson.put("msg", "消费金额不能为空且大于0");
                resultJson.put("result", false);
                return resultJson;
            }

            //使用redis进行简单的加锁，避免重复处理改订单
            if (!redissonUtil.lock(consumeId)) {
                resultJson.put("code", "0002");
                resultJson.put("msg", "订单已在处理");
                resultJson.put("result", false);
                return resultJson;
            }

            //进行扣费操作，首先需要判断用户余额是否大于100，不大于100直接返回消费失败

            JSONObject userDTO = new JSONObject();
            userDTO.put("userId",userId);
            JSONObject entries = this.queryBalance(userDTO);

            BigDecimal balance = new BigDecimal(entries.getStr("balance"));//用户余额
            BigDecimal money = new BigDecimal(entries.getStr(consumeMoney));//消费金额

            if (balance.compareTo(money)<0){
                //消费金额大于用户余额，扣费失败
                resultJson.put("code", "0003");
                resultJson.put("msg", "余额不足");
                resultJson.put("result", false);
                return resultJson;
            }

            //用户余额充足，正常扣费
            BigDecimal balanceNew = balance.subtract(money).setScale(2, BigDecimal.ROUND_HALF_UP);//消费后余额

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String updateTime = sdf.format(new Date());


            String balanceSql = "update tb_user set balance='"+balanceNew+"',update_time='" + updateTime + "' where user_id='" + userId + "'";

            //事务判断
            boolean result = true;

            if ("".equals(balanceSql)){//判断balanceSql是否执行成功,扣费成功
                //balanceSql执行成功,扣费成功
                System.out.println("操作mybatis或mybatis plus框架执行上面sql："+balanceSql);//扣费成功

                //插入消费记录表
                //INSERT INTO `test`.`tb_consume` (`consume_id`, `user_id`, `consume_money`, `consume_status`, `remark`, `create_time`, `update_time`) VALUES (1, 1, 100, '1', '成功消费100元', '2023-10-18 20:47:12', '2023-10-18 20:47:18');
                String consumeSql = "insert into tb_consume (`consume_id`, `user_id`, `consume_money`, `consume_status`, `remark`, `create_time`, `update_time`) " +
                        "VALUES ('"+consumeId+"', '"+userId+"', '"+consumeMoney+"', '1', '"+remark+"', '"+updateTime+"', '"+updateTime+"')";
                //consumeSql执行成功,扣费成功
                System.out.println("操作mybatis或mybatis plus框架执行上面sql："+consumeSql);//插入消费记录表成功

                //插入账户余额变动明细表  change_type：变动类型（0：增加，1：减少）
                //INSERT INTO `test`.`tb_balance_change` (`balance_change_id`, `consume_id`, `refund_id`, `user_id`, `change_money`, `change_money_before`, `change_money_later`, `change_type`, `change_status`, `remark`, `create_time`, `update_time`) VALUES (1, 1, NULL, 1.00, 100.00, 1000.00, 900.00, '1', '1', '消费100元', '2023-10-18 21:00:01', '2023-10-18 21:00:04');
                String changeSql = "insert into tb_balance_change (`consume_id`, `user_id`, `change_money`, `change_money_before`, `change_money_later`, `change_type`, `change_status`, `remark`, `create_time`, `update_time`) " +
                        "VALUES ('"+consumeId+"', '"+userId+"', '"+consumeMoney+"', '"+balance+"', '"+balanceNew+"','1','1','"+remark+"', '"+updateTime+"', '"+updateTime+"')";
                //consumeSql执行成功,扣费成功
                System.out.println("操作mybatis或mybatis plus框架执行上面sql："+changeSql);//插入消费记录表成功

                //所以操作执行成功后，变更事务判断
                result = false;
            }



            if (result){
                //所以操作有一项没成功就退回之前

                String resTime = sdf.format(new Date());
                log.error("账户余额回滚：update tb_user set balance='"+balance+"',update_time='" + resTime + "' where user_id='" + userId + "'");

                log.error("消费记录表回滚：" + "DELETE FROM tb_consume WHERE consume_id = '" + consumeId + "'");

                log.error("账户余额变动明细表回滚：" + "DELETE FROM tb_balance_change WHERE consume_id = '" + consumeId + "'"));

                log.error("扣费接口失败，已退回");
            }


            resultJson.put("code", "0000");
            resultJson.put("msg", "消费成功");
            resultJson.put("result", true);

        } catch (Exception e) {
            e.printStackTrace();
            log.error("消费出现了异常:", e);
            resultJson.put("code", "0004");
            resultJson.put("msg", "消费出现异常");
            resultJson.put("result", false);
        } finally {
            //防止因为异常导致解锁失败，执行完成后再次调用解锁，防止未解锁导致锁一直在刷新
            redissonUtil.unlock(consumeId);
        }
        return resultJson;
    }

    @Override
    public JSONObject refund(JSONObject refundDTO) {
        //初始化返回结果
        JSONObject resultJson = new JSONObject();

        String consumeId = "",refundId = "",userId = "", refundMoney = "",remark = "";

        try {

            consumeId = refundDTO.getStr("consumeId");
            refundId = refundDTO.getStr("refundId");
            userId = refundDTO.getStr("userId");
            refundMoney = refundDTO.getStr("refundMoney");//退款金额传入20
            remark = refundDTO.getStr("remark");

            //判断入参
            if (!"".equals(consumeId)) {
                resultJson.put("code", "0001");
                resultJson.put("msg", "消费id不能为空");
                resultJson.put("result", false);
                return resultJson;
            }
            if (!"".equals(refundId)) {
                resultJson.put("code", "0001");
                resultJson.put("msg", "退款id不能为空");
                resultJson.put("result", false);
                return resultJson;
            }
            if (!"".equals(userId)) {
                resultJson.put("code", "0001");
                resultJson.put("msg", "用户id不能为空");
                resultJson.put("result", false);
                return resultJson;
            }
            if (!"".equals(refundMoney) && new BigDecimal("0").compareTo(new BigDecimal(refundMoney))<0) {
                resultJson.put("code", "0001");
                resultJson.put("msg", "退款金额不能为空且大于0");
                resultJson.put("result", false);
                return resultJson;
            }

            //退款操作也是需要事务的，由于节约时间，上面消费接口也简单实现事务思想了，下面我就不做事务代码了

            //进行退款操作，首先需要该订单是否大于退款金额，不大于20直接返回消费失败
            JSONObject userDTO = new JSONObject();
            userDTO.put("userId",userId);
            JSONObject entries = this.queryBalance(userDTO);

            BigDecimal balance = new BigDecimal(entries.getStr("balance"));//用户余额
            BigDecimal money = new BigDecimal(entries.getStr(refundMoney));//退款金额20元

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String updateTime = sdf.format(new Date());


            BigDecimal balanceNew = balance.add(money).setScale(2, BigDecimal.ROUND_HALF_UP);//退款后余额

            String balanceSql = "update tb_user set balance='"+balanceNew+"',update_time='" + updateTime + "' where user_id='" + userId + "'";

            if ("".equals(balanceSql)){//判断balanceSql是否执行成功,扣费成功
                //balanceSql执行成功,扣费成功
                System.out.println("操作mybatis或mybatis plus框架执行上面sql："+balanceSql);//扣费成功

                //退款操作一般我们是使用冲正的方式实现，也就是通过充值来退款，这样方便后续系统对账
                //INSERT INTO `test`.`tb_recharge` (`recharge_id`, `user_id`, `recharge_money`, `recharge_status`, `remark`, `create_time`, `update_time`) VALUES (1, 1, 20, '1', '订单冲正', '2023-10-19 10:21:45', '2023-10-19 10:21:50');
                String rechargeSql = "insert into tb_recharge (, `user_id`, `recharge_money`, `recharge_status`, `remark`, `create_time`, `update_time`) " +
                        "VALUES ( '"+userId+"', '"+money+"', '1', '订单冲正（退款操作）', '"+updateTime+"', '"+updateTime+"')";

                //更新消费记录表
                String consumeSql = "update tb_consume set remark='已退款"+money+"元',update_time='" + updateTime + "' where consume_id='" + consumeId + "'";

                //插入退款表
                //INSERT INTO `test`.`tb_refund` (`refund_id`, `consume_id`, `user_id`, `refunde_money`, `refund_status`, `remark`, `create_time`, `update_time`) VALUES (1, 1, 1, 20.00, '1', '11', '2023-10-19 10:32:40', '2023-10-19 10:32:43');
                String refundSql = "insert into tb_refund (`refund_id`,`consume_id`, `user_id`, `refunde_money`, `refund_status`, `remark`, `create_time`, `update_time`) " +
                        "VALUES ('"+refundId+"','"+consumeId+"', '"+userId+"', '"+money+"', '1','"+remark+"', '"+updateTime+"', '"+updateTime+"')";
                //consumeSql执行成功,扣费成功
                System.out.println("操作mybatis或mybatis plus框架执行上面sql："+refundSql);//插入消费记录表成功

                //插入账户余额变动明细表  change_type：变动类型（0：增加，1：减少）
                //INSERT INTO `test`.`tb_balance_change` (`balance_change_id`, `consume_id`, `refund_id`, `user_id`, `change_money`, `change_money_before`, `change_money_later`, `change_type`, `change_status`, `remark`, `create_time`, `update_time`) VALUES (1, 1, NULL, 1.00, 100.00, 1000.00, 900.00, '1', '1', '消费100元', '2023-10-18 21:00:01', '2023-10-18 21:00:04');
                String changeSql = "insert into tb_balance_change (`refund_id`, `user_id`, `change_money`, `change_money_before`, `change_money_later`, `change_type`, `change_status`, `remark`, `create_time`, `update_time`) " +
                        "VALUES ('"+refundId+"', '"+userId+"', '"+money+"', '"+balance+"', '"+balanceNew+"','0','1','"+remark+"', '"+updateTime+"', '"+updateTime+"')";
                //consumeSql执行成功,扣费成功
                System.out.println("操作mybatis或mybatis plus框架执行上面sql："+changeSql);//插入消费记录表成功


            }

            resultJson.put("code", "0000");
            resultJson.put("msg", "退款成功");
            resultJson.put("result", true);

        } catch (Exception e) {
            e.printStackTrace();
            log.error("退款出现了异常:", e);
            resultJson.put("code", "0004");
            resultJson.put("msg", "退款异常");
            resultJson.put("result", false);
        }
        return resultJson;
    }

    @Override
    public JSONObject queryBalanceChange(JSONObject changeDTO) {
        //初始化返回结果
        JSONObject resultJson = new JSONObject();

        //由于上面消费接口和退款接口已经对余额变动表做了记录，所以这个接口直接查询即可，可以根据时间和用户id查询

        try {
            String condition = "";
            //判断入参
            if (!"".equals(changeDTO.getStr("userId"))) {
                condition = "and tb_balance_change.user_id = '"+changeDTO.getStr("userId")+"'";
            }

            //查询sql语句  这里最好是要分页了，使用limit 0,10
            String sql = "select * from tb_balance_change "
                    + " where create_time between '"+changeDTO.getStr("startTime")+"' and '"+changeDTO.getStr("endTime")+"'" + condition;
            System.out.println("操作mybatis或mybatis plus框架执行上面sql："+sql);
            Integer queryTotal = 1;//查询结果数量
            if (queryTotal > 0){
                resultJson.put("code", "0000");
                resultJson.put("data", sql);//将查询到的json对象put进去
                resultJson.put("msg", "查询成功");
                resultJson.put("result", true);
            }else {
                resultJson.put("code", "0000");
                resultJson.put("msg", "未查询到变动信息");
                resultJson.put("result", true);
            }
        } catch (JSONException e) {
            log.error("查询到变动信息接口出现了异常:",e);
        }
        return resultJson;
    }
}
